package proyecto;

import java.util.ArrayList;

import proyecto.Mind.state;
import es.upv.dsic.gti_ia.core.ACLMessage;
import json.JsonObject;
import es.upv.dsic.gti_ia.core.AgentID;
import es.upv.dsic.gti_ia.core.SingleAgent;


/**
 * @author Sergio Damián Delgado González
 *
 */
public class Drone extends SingleAgent {
    private final int Enviar_Posicion = 0, LIBERAR = 1;
    private int status;
    private ACLMessage inbox, outbox;
    private boolean exit;

    //Enum with the possible dron's movements
    enum move { NORTH,
    			EAST,
    			SOUTH,
    			WEST};
    			
    private move lastMove;
    private boolean deadEnd=false;
       
    //Objeto JSON
    private JsonObject obj;
    String informacion;
    
    //Dronsmind
    private Mind dronsMind;
    double angle;
    
    ArrayList<state> values;
    ArrayList<move> movements;
    ArrayList<move> aux;
    
    /** droneWay **/
    private ArrayList<Pair> way;
    
    
    
    
    public Drone(AgentID aid, Pair pos ,int initialBatteryCharge) throws Exception  {
        
        super(aid);
        //Create memory's dron
        dronsMind = new Mind(initialBatteryCharge);
        dronsMind.setPosX(pos.getFirst());
        dronsMind.setPosY(pos.getSecond());
    }
    
    public void init(int initialBatteryCharge)  {
        System.out.println("Drone("+this.getName()+") Iniciando");
        status = Enviar_Posicion;
        inbox = null;
        outbox = null;
        exit = false;
        
 
        //Poner al maximo
        dronsMind.createMind(500,500);
        way = new ArrayList<Pair>();
        way.add(new Pair(0, 0));
        
        obj= new JsonObject().add( "posx", dronsMind.getPosX() ).add( "posy", dronsMind.getPosY() );
        //informacion=obj.toString();
        
        values = new ArrayList<state>();
        movements = new ArrayList<move>();
        
        lastMove = move.NORTH;
        
    }
    
    public void execute()  {
    	
        System.out.println("Dron("+this.getName()+") Ejecución");
        
        while (!exit)  {
            switch(status)  {
                case Enviar_Posicion:
                	
                	//System.out.println("Drone("+this.getName()+") Interrogando");            
                    outbox = new ACLMessage();
                    outbox.setSender(this.getAid());
                    outbox.addReceiver(new AgentID("Anderson"));
                    if (deadEnd){
                    	outbox.setPerformative(ACLMessage.FAILURE);
                    }
                    else{
                        outbox.setPerformative(ACLMessage.REQUEST);                    	
                    }
                    informacion=obj.toString();
                    outbox.setContent(informacion);                
                    this.send(outbox);

                    try {
                        inbox = receiveACLMessage();                        
                        
                        //System.out.println( "NORTE = "+obj.get( "casi_nort" ).asInt() );
                        //System.out.println(" DROIDE " + obj.get( "dist" ).asInt());
             
                    } catch (InterruptedException ex) {
                    	System.err.println("Drone("+this.getName()+") Error de comunicación");
                        exit = true;
                    }
                    if ( inbox.getPerformative().equals("AGREE") ){
                    	status = LIBERAR;
                    	//System.out.println(" AGRREE DEL SATELITE LLEGA A DRONE");
                    }
                    if (inbox.getPerformative().equals("REFUSE")){
                        informacion = inbox.getContent();
                        obj= JsonObject.readFrom( informacion );
                    	//System.out.println(" POR AQUI ");
                    	
                    	 //Reaccionar aquí en consecuencia a partir de la informacion del satelite
                        angle = obj.get( "angl"  ).asDouble();
                        //System.out.println("Angulo = "+angle);
                        
                        //System.out.println(" POR AQUI2 ");
                        values.clear();
                        movements.clear();
                        values.add( getState (obj.get( "casi_nort" ).asInt()));
                        values.add( getState (obj.get( "casi_ne" ).asInt()) );
                        values.add( getState (obj.get( "cas_est" ).asInt()) );
                        values.add( getState (obj.get( "casi_se" ).asInt()) );
                        values.add( getState (obj.get( "cas_sur" ).asInt()) );
                        values.add( getState (obj.get( "ca_sw" ).asInt()) );
                        values.add( getState (obj.get( "cas_oest" ).asInt()) );
                        values.add( getState (obj.get( "ca_nw" ).asInt()) );
                        //System.out.println(" POR AQUI3 ");
                        
                        aux = dronsMind.areThereCrossedPlaces( );


                    	//Actualizamos memoria
                        dronsMind.set (dronsMind.getPosX(), dronsMind.getPosY() , values);
                        //dronsMind.show();
                        
                        //Función que elige las posiciones a las que podría moverse
                        //System.out.println( "values = "+values );
                        dronsMind.possibleMovements(movements, values);
                        System.out.println( "Movements despues de possibleMovements "+movements );
                        
                        //Función que tras consultar la memoria decide donde moverse
                        dronsMind.think(movements);
                        System.out.println( "Movements despues de think "+movements );
                        
                        //Función que ordena las opciones de mejor a peor
                        dronsMind.sortMovements(angle,movements);
                        System.out.println( "Movements despues de sortMovements "+ movements );
                        
                        //Función que tras consultar la memoria decide donde moverse
                        dronsMind.think(movements);
                        System.out.println( "Movements despues de segundo think "+movements );
                        
                        lastMove = movements.get(0);
                        System.out.println( "Voy a moverme a <<"+movements.get(0)+ ">> porque:" );
                        dronsMind.showPos(dronsMind.getPosX(),dronsMind.getPosY());
                        //System.out.println( "Ahora estoy en "+dronsMind.getPosX()+","+dronsMind.getPosY() );
                        
                        //Voy a moverme, actualizar pos Drone
                        switch (lastMove){
                            case NORTH: dronsMind.setPosX( dronsMind.getPosX()-1 );
                            			break;
                            case EAST:	dronsMind.setPosY( dronsMind.getPosY()+1 );
                            			break;
                            case SOUTH:	dronsMind.setPosX( dronsMind.getPosX()+1 );
                            			break;
                            case WEST:	dronsMind.setPosY( dronsMind.getPosY()-1 );
                        				break;
                        }
                        //System.out.println( "Y ahora estoy en "+dronsMind.getPosX()+","+dronsMind.getPosY() );

                        way.add(new Pair(dronsMind.getPosX(),dronsMind.getPosY()));
                        
                        //Actualizar la posicion para que el satélite lo sepa
                        obj.set( "posx" , dronsMind.getPosX() );
                        obj.set( "posy" , dronsMind.getPosY() );

                }
                
                //System.out.println("FINAL DE ENVIAR_POSICION EN DRONE");
                //dronsMind.show();
                break;
                case LIBERAR:
                	
                	System.out.println("Dron("+this.getName()+") Target found! Let's drink beer!");
                	System.out.println("La secuencia es: ");
                	for ( int i=0; i<way.size() ; ++i ){
                		System.out.print("["+way.get(i).getFirst()+",");
                		System.out.print(way.get(i).getSecond()+"]");
                		if ((i+1)%10 == 0){
                			System.out.println("");
                		}
                	}
                	System.out.println("");
                    outbox = new ACLMessage();
                    outbox.setSender(this.getAid());
                    outbox.addReceiver(new AgentID("Anderson"));
                    outbox.setPerformative(ACLMessage.CONFIRM);
                    this.send(outbox);
                    exit = true;
                    //dronsMind.show();
                    break;
            }
        }
    }
    

	private state getState(int uuu) {
		state aux = state.OUTOFRANGE;
		//System.out.println("==== "+uuu);
		switch (uuu){
		case 0: aux = state.UNCROSSED;
				break;
		case -1:aux = state.OBSTACLE;
				break;
		case 2: aux = state.TARGET;
				break;
		default:
				aux = state.OUTOFRANGE;
		}
		return aux;
	}

	public void finalize()  {
        System.out.println("Dron("+this.getName()+") Terminando");
    }
}